﻿/// <reference path="jquery.js" />
/// <reference path="svg.js" />
/// <reference path="pv.core.js" />
/// <reference path="database.js" />

var pro = {
    init: function (target, handle, type, svg, mousedown, mousemove, launch, refreshMouseMovedDis) {
        function move(event) {
            if (target.isPicked) {
                var posi = getPosition(event);
                //if (pv.isInBoundary(posi)) {
                if (pv.isInVillage(posi))
                    mousemove(posi);
                else {
                    pro.pickup(target, false, svg);
                    launch();
                }
                // }
                //                else
                //                    pro.pickup(target, false, svg);
            }
        }

        handle.bind("touchstart", function (e) {
            mousedown(e);
            pro.pickup(target, true, svg);
        });

        handle.mousedown(function (e) {
            mousedown(e);
            pro.pickup(target, true, svg);
        });

        handle.bind("touchend", function (e) {
            pro.pickup(target, false, svg);
            launch();
        });

        handle.mouseup(function (e) {
            pro.pickup(target, false, svg);
            launch();
        });

        svg.mouseleave(function (e) {
            pro.pickup(target, false, svg);
            // launch();
        });

        svg.bind("touchmove", function (event) {
            event.preventDefault();
            move(event);
        });

        svg.mousemove(function (event) {
            move(event);
        });


        pv.setTimer(target, null, refreshMouseMovedDis);
    },

    calSpeed: function (diff, speed_r) {
        if (speed_r > 0) {
            var r = geo.vectorNorm(diff);
            if (Math.abs(r.x * speed_r) < Math.abs(diff.x) && Math.abs(r.y * speed_r) < Math.abs(diff.y))
                diff = { x: diff.x - r.x * speed_r, y: diff.y - r.y * speed_r };
            else diff = { x: 0, y: 0 };
        }
        return diff;
    },

    pickup: function (target, picked, svg, opts) {
        opts = $.extend({
            animate: function (picked) {
                if (picked) {
                    //target.svgAddClass("shadow");
                    //target.setScale(1.2);
                }
                else {
                    // target.svgRemoveClass("shadow");
                    target.setScale(1);
                }
            }
        }, opts || {});

        target.isPicked = picked;
        if (picked) {
            svg.append(target);
            target.attr("pv-picked", "picked");
            //if (animate)
            opts.animate(picked);
        }
        else {
            target.removeAttr("pv-picked");
            opts.animate(picked);
        }
    },

    detectTarget: function (target, type, currentCentre, svg) {
        var detectedTargets = [];
        svg.find("[pv-cat='target']").each(function () {
            var targetRadius = $(this).attr("pv-radius");
            if (targetRadius) {
                targetRadius = parseFloat(targetRadius);
                targetPosi = $(this).getTranslate();

                if (geo.dist2p(targetPosi, currentCentre) - type.radius - targetRadius < 0)
                    detectedTargets.push($(this));
            }
        });

        if (detectedTargets.length > 0) {
            //type.effect(target, { projectile: type, targets: detectedTargets });
            type.attach(target, { projectile: type, targets: detectedTargets }); //type.demage, target, detectedTargets);
        }
    }
};

$.fn.createProjectile = function (id, position, opts) {
    var svg = $(this);
    var type = getType(id, projectiles);
    var target = svg.createNode(type, "projectile", position.x, position.y, opts);

    //-------------------------------
    var currentCentre = target.getTranslate();
    var preCentre = currentCentre;
    var preCursorPosi = currentCentre;
    var mouseMovedDis = null;

    var currentRotation = 0;

    var currentSpinAngle = 0;
    var spinInterval = null;

    function launch() {
        var sec = type.fly_time;
        // target.setScale(0.9);

        var diff = { x: mouseMovedDis.x, y: mouseMovedDis.y };
        pv.setTimer(target, sec, function () {
            if (!pv.isInBoundary(currentCentre)) {
                pro.pickup(target, false, svg);

                return true;
            }

            if (type.spinnable) {
                var diffOff = 0;
                if (currentSpinAngle < 0)
                    diffOff = geo.vectorNorm(geo.vectorPerpLeft(diff));
                else if (currentSpinAngle > 0)
                    diffOff = geo.vectorNorm(geo.vectorPerpRight(diff));
                if (currentSpinAngle != 0) {
                    var spin_off = Math.abs(currentSpinAngle * type.spin_off);
                    diff = geo.vectorAdd(diff, { x: diffOff.x * spin_off, y: diffOff.y * spin_off });
                }
            }

            diff = pro.calSpeed(diff, type.speed_r);

            currentCentre = { x: (currentCentre.x + diff.x + pv.wind.x * type.windage), y: (currentCentre.y + diff.y + pv.wind.y * type.windage) };
            target.setTranslate(currentCentre.x, currentCentre.y);

            pro.detectTarget(target, type, currentCentre, svg);

        }, function () {
            if (!pv.isInVillage(currentCentre)) {
                //target.dispose();
                type.land.after(target, {});
            }
        });
    };

    function mousedown(e) {
        preCursorPosi = getPosition(e);
    }

    function mousemove(posi) {
        var dis = { x: (posi.x - preCursorPosi.x), y: (posi.y - preCursorPosi.y) };
        currentCentre = { x: (currentCentre.x + dis.x), y: (currentCentre.y + dis.y) };

        if (type.spinnable) {
            var offset = svg.offset();
            var angle = geo.angle3p(currentCentre, preCursorPosi, posi);

            if (angle) {
                if (currentSpinAngle * angle < 0 || Math.abs(currentSpinAngle) < Math.abs(angle * type.spin_a)) {
                    currentSpinAngle = angle * type.spin_a;
                    if (spinInterval)
                        clearInterval(spinInterval);

                    spinInterval = setInterval(function () {
                        var rot = target.getRotate();
                        rot = target.getRotate();
                        target.setRotate(rot + currentSpinAngle);
                        if (Math.abs(currentSpinAngle) >= type.spin_r) {
                            if (angle > 0) {
                                currentSpinAngle -= type.spin_r;
                            }
                            else
                                currentSpinAngle += type.spin_r;
                        }
                        else {
                            currentSpinAngle = 0;
                            clearInterval(spinInterval);
                            spinInterval = null;
                        }
                    }, pv.frameInterval);
                }
            }
        }

        target.setTranslate(currentCentre.x, currentCentre.y);

        if (type.auto_rotate) {
            var angle = geo.vectorDir(mouseMovedDis);
            if (angle) {
                target.setRotate(angle);
            }
        }

        preCursorPosi = posi;
    }

    //detect speed
    function refreshMouseMovedDis() {
        if (preCentre != null)
            mouseMovedDis = { x: currentCentre.x - preCentre.x, y: currentCentre.y - preCentre.y };
        preCentre = currentCentre;
    }

    pro.init(target, target, type, svg, mousedown, mousemove, launch, refreshMouseMovedDis);

    return target;
};

$.fn.createChainProjectile = function (id, position, opts) {
    var $target = $(this);

    var type = getType(id, chainProjectiles, { defaultType: projectiles[0] });
    var node = $(this).createNode(type, "projectile", position.x, position.y, opts);

    //------------------------
    var handle = node.find("[pv-chain='0']");
    var payload = node.find("[pv-chain='last']");

    var preCentre = null;
    var currentCentre = handle.getTranslate();
    var mouseMovedDis = null;

    var prePayLoadCentre = null;
    var currentPayLoadCentre = payload.getTranslate();
    var payloadMovedDis = null;

    var preCursorPosi = null;
    var currentRotation = 0;

    function launch() {
        sec = type.fly_time;

        if (payloadMovedDis) {
            //node.setScale(0.9);

            var diff = payloadMovedDis;

            var angle = geo.vectorDir(diff)
            //payload.setRotate(angle);

            var radianangle = angle * Math.PI / 180;

            pv.setTimer(node, sec, function () {
                if (!pv.isInBoundary({ x: currentPayLoadCentre.x + position.x, y: currentPayLoadCentre.y + position.y }) || node.isPicked && pv.isInVillage({ x: currentPayLoadCentre.x + position.x, y: currentPayLoadCentre.y + position.y })) {
                    prePayLoadCentre = null;
                    currentCentre = handle.getTranslate();
                    return true;
                }

                diff = pro.calSpeed(diff, type.speed_r);
                currentPayLoadCentre = { x: (currentPayLoadCentre.x + diff.x + pv.wind.x * type.windage), y: (currentPayLoadCentre.y + diff.y + pv.wind.y * type.windage) };
                payload.setTranslate(currentPayLoadCentre.x, currentPayLoadCentre.y);
                if (angle)
                    payload.setRotate(angle);
                var x1 = currentPayLoadCentre.x + type.payload_offset * Math.sin(-radianangle);
                var y1 = currentPayLoadCentre.y + type.payload_offset * Math.cos(-radianangle);

                updateChainPosition(x1, y1, handle, type.handle_offset, false, false);

                pro.detectTarget(node, type, { x: currentPayLoadCentre.x + position.x, y: currentPayLoadCentre.y + position.y }, $target);

            }, function () {
                if (!pv.isInVillage({ x: currentPayLoadCentre.x + position.x, y: currentPayLoadCentre.y + position.y }))
                    node.dispose();
            });
        }
    };

    function updateChainPosition(x1, y1, last, last_offset, isToward, isUpdatePayloadPosi) {
        function updateChain(ci) {
            var chain = node.find("[pv-chain='" + ci + "']");

            if (isToward) {
                var x2 = parseFloat(chain.attr("x2"));
                var y2 = parseFloat(chain.attr("y2"));
            }
            else {
                var x2 = parseFloat(chain.attr("x1"));
                var y2 = parseFloat(chain.attr("y1"));
            }

            var angle2 = geo.vectorDir({ x: x2 - x1, y: y2 - y1 });
            var radianangle2 = angle2 * Math.PI / 180;

            var x2 = x1 + type.chain_len * Math.sin(radianangle2);
            var y2 = y1 - type.chain_len * Math.cos(radianangle2);

            if (isToward)
                chain.attr({ x1: x1, y1: y1, x2: x2, y2: y2 });
            else
                chain.attr({ x2: x1, y2: y1, x1: x2, y1: y2 });

            x1 = x2;
            y1 = y2;
        }
        if (isToward) {
            for (var ci = 1; ci <= type.chain_num; ci++) {
                updateChain(ci);
            }
        }
        else {
            for (var ci = type.chain_num; ci >= 1; ci--) {
                updateChain(ci);
            }
        }

        lastPosi = { x: x1, y: y1 };

        var currentLastCentre = last.getTranslate();

        if (isUpdatePayloadPosi)
            currentPayLoadCentre = currentLastCentre;

        var lastAngle = geo.vectorDir({ x: currentLastCentre.x - lastPosi.x, y: currentLastCentre.y - lastPosi.y });

        radianLastAngle = lastAngle * Math.PI / 180;

        var lastX = lastPosi.x + last_offset * Math.sin(radianLastAngle);
        var lastY = lastPosi.y - last_offset * Math.cos(radianLastAngle);

        last.setTranslate(lastX, lastY);
        last.setRotate(lastAngle);

        return { x: x1, y: y1 };
    }

    function mousemove(posi) {
        var dis = { x: (posi.x - preCursorPosi.x), y: (posi.y - preCursorPosi.y) };
        currentCentre = { x: (currentCentre.x + dis.x), y: (currentCentre.y + dis.y) };

        handle.setTranslate(currentCentre.x, currentCentre.y);
        var angle = null;
        if (type.auto_rotate) {
            angle = geo.vectorDir(mouseMovedDis);
            if (angle) {
                handle.setRotate(angle);
            }
        }

        var radianangle = angle * Math.PI / 180;
        var x1 = currentCentre.x + type.handle_offset * Math.sin(-radianangle);
        var y1 = currentCentre.y + type.handle_offset * Math.cos(-radianangle);

        updateChainPosition(x1, y1, payload, type.payload_offset, true, true);

        //        if (node.isPicked && !pv.isInVillage(posi)) {
        //            pro.pickup(node, false, $target);
        //            launch(type.fly_time);
        //        }
        preCursorPosi = posi;


    }

    //detect speed
    function refreshMouseMovedDis() {
        if (preCentre != null)
            mouseMovedDis = { x: currentCentre.x - preCentre.x, y: currentCentre.y - preCentre.y };
        preCentre = currentCentre;

        if (prePayLoadCentre != null && currentPayLoadCentre != null)
            payloadMovedDis = { x: currentPayLoadCentre.x - prePayLoadCentre.x, y: currentPayLoadCentre.y - prePayLoadCentre.y };


        prePayLoadCentre = currentPayLoadCentre;
    }

    //    handle.mouseleave(function () {
    //        pro.pickup(node, false, $target);
    //    });

    pro.init(node, handle, type, $target, function (e) {
        preCursorPosi = getPosition(e); prePayLoadCentre = currentPayLoadCentre;
    }, mousemove, launch, refreshMouseMovedDis);

    return node;
};

